﻿using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Hourglass.Qrobot.Http;
using Hourglass.Qrobot.Models;
using Hourglass.Qrobot.Utils;

namespace Hourglass.Qrobot
{
    public static class ContextExtension
    {
        #region Extrat Request From Context

        public static LoginQRCodeRequest ToLoginQrCodeRequest(this QQContext context)
        {
            return new LoginQRCodeRequest
            {
                AppId = context.Config.AppId,
                CookieContainer = context.CookieHolder
            };
        }

        public static LoginScanStatusRequest ToLoginScanStatusRequest(this QQContext context)
        {
            return new LoginScanStatusRequest
            {
                AppId = context.Config.AppId,
                CookieContainer = context.CookieHolder
            };
        }

        public static LoginSigCheckRequest ToLoginSigCheckRequest(this QQContext context, string url)
        {
            return new LoginSigCheckRequest
            {
                Url = url,
                CookieContainer = context.CookieHolder
            };
        }

        public static LoginVfwebqqRequest ToLoginVfwebqqRequest(this QQContext context, long milliscond)
        {
            return new LoginVfwebqqRequest
            {
                ClientId = context.Config.ClientId,
                Ptwebqq = context.VerfiedField.Ptwebqq,
                RefererV = context.Config.RefererV1,
                Milliscond = milliscond,
                CookieContainer = context.CookieHolder
            };
        }

        public static LoginPsessionRequest ToLoginPsessionRequest(this QQContext context)
        {
            return new LoginPsessionRequest
            {
                ClientId = context.Config.ClientId,
                Ptwebqq = context.VerfiedField.Ptwebqq,
                RefererV = context.Config.RefererV2,
                CookieContainer = context.CookieHolder
            };
        }

        public static LoadFriendRequest ToLoadFriendRequest(this QQContext context)
        {
            return new LoadFriendRequest
            {
                Vfwebqq = context.VerfiedField.Vfwebqq,
                QHash = context.VerfiedField.Qhash,
                RefererV = context.Config.RefererV1,
                CookieContainer = context.CookieHolder
            };
        }

        public static LoadGroupRequest ToLoadGroupRequest(this QQContext context)
        {
            return new LoadGroupRequest
            {
                Vfwebqq = context.VerfiedField.Vfwebqq,
                QHash = context.VerfiedField.Qhash,
                RefererV = context.Config.RefererV1,
                CookieContainer = context.CookieHolder
            };
        }

        public static LoadDisscussRequest ToLoadDisscussRequest(this QQContext context, long milliscond)
        {
            return new LoadDisscussRequest
            {
                ClientId = context.Config.ClientId,
                Psessionid = context.VerfiedField.Psessionid,
                Vfwebqq = context.VerfiedField.Vfwebqq,
                RefererV = context.Config.RefererV1,
                Milliscond = milliscond,
                CookieContainer = context.CookieHolder
            };
        }

        public static LoadOwnerInfoRequest ToLoadOwnerInfoRequest(this QQContext context, long milliscond)
        {
            return new LoadOwnerInfoRequest
            {
                RefererV = context.Config.RefererV1,
                Milliscond = milliscond,
                CookieContainer = context.CookieHolder
            };
        }

        public static LoadRecentRequest ToLoadRecentRequest(this QQContext context)
        {
            return new LoadRecentRequest
            {
                ClientId = context.Config.ClientId,
                Psessionid = context.VerfiedField.Psessionid,
                Vfwebqq = context.VerfiedField.Vfwebqq,
                RefererV = context.Config.RefererV2,
                CookieContainer = context.CookieHolder
            };
        }

        public static LoadOnlineRequest ToLoadOnlineRequest(this QQContext context, long milliscond)
        {
            return new LoadOnlineRequest
            {
                ClientId = context.Config.ClientId,
                Psessionid = context.VerfiedField.Psessionid,
                Vfwebqq = context.VerfiedField.Vfwebqq,
                RefererV = context.Config.RefererV2,
                Milliscond = milliscond,
                CookieContainer = context.CookieHolder
            };
        }

        public static LoadFriendInfoRequest ToLoadFriendInfoRequest(this QQContext context, long friendId, long milliscond)
        {
            return new LoadFriendInfoRequest
            {
                ClientId = context.Config.ClientId,
                Psessionid = context.VerfiedField.Psessionid,
                Vfwebqq = context.VerfiedField.Vfwebqq,
                RefererV = context.Config.RefererV1,
                FriendId = friendId,
                Milliscond = milliscond,
                CookieContainer = context.CookieHolder
            };
        }

        public static LoadGroupInfoRequest ToLoadGroupInfoRequest(this QQContext context, long groupCode, long milliscond)
        {
            return new LoadGroupInfoRequest
            {
                Vfwebqq = context.VerfiedField.Vfwebqq,
                GroupCode = groupCode,
                RefererV = context.Config.RefererV1,
                Milliscond = milliscond,
                CookieContainer = context.CookieHolder
            };
        }

        public static LoadDisscussInfoRequest ToLoadDisscussInfoRequest(this QQContext context, long disscussId, long milliscond)
        {
            return new LoadDisscussInfoRequest
            {
                ClientId = context.Config.ClientId,
                Psessionid = context.VerfiedField.Psessionid,
                Vfwebqq = context.VerfiedField.Vfwebqq,
                RefererV = context.Config.RefererV2,
                DisscussId = disscussId,
                Milliscond = milliscond,
                CookieContainer = context.CookieHolder
            };
        }

        public static PollRequest ToPollRequest(this QQContext context)
        {
            return new PollRequest
            {
                ClientId = context.Config.ClientId,
                Psessionid = context.VerfiedField.Psessionid,
                Ptwebqq = context.VerfiedField.Ptwebqq,
                RefererV = context.Config.RefererV2,
                CookieContainer = context.CookieHolder
            };
        }

        public static T ToAccountNumberRequest<T>(this QQContext context, long id, long milliscond) where T : AccountNumberRequest, new()
        {
            return new T
            {
                IdOrCode = id,
                Milliscond = milliscond,
                Vfwebqq = context.VerfiedField.Vfwebqq,
                CookieContainer = context.CookieHolder
            };
        }

        #endregion Extrat Request From Context

        #region Context Member Extension

        public static Friend FindOrLoadFriendById(this QQContext context, long id)
        {
            if (context.Qq.ContainsFriend(id))
            {
                return context.Qq.FindFriendById(id);
            }
            var returnedFriendInfo = DataProvider.LoadFriendInfo(context.ToLoadFriendInfoRequest(id, TimeHelper.MilliscondFromSeventy()));
            if (returnedFriendInfo == null) return null;
            context.ReloadFriends(TimeHelper.MilliscondFromSeventy());
            if (context.Qq.ContainsFriend(id))
            {
                return context.Qq.FindFriendById(id);
            }
            var friend = new Friend {Id = returnedFriendInfo.Uin};
            friend.ApplyReturned(returnedFriendInfo);

            return friend;
        }

        public static GroupMember FindOrLoadGroupMemberByName(this QQContext context, string markName, long groupCode)
        {
            if (context.Qq.ContainsGroup(groupCode))
            {
                var member = context.Qq.FindMemberFromGroupByName(markName, groupCode);
                if (member != null) return member;
                if (SmartQQ.IsAtAll(markName)) return null;
            }
            var returnedGroupInfo = DataProvider.LoadGroupInfo(context.ToLoadGroupInfoRequest(groupCode, TimeHelper.MilliscondFromSeventy()));
            if (returnedGroupInfo == null) return null;
            var group = returnedGroupInfo.ConvertToView();
            context.Qq.AddGroup(group);
            return group.FindMemberByName(markName);
        }

        public static GroupMember FindOrLoadGroupMemberById(this QQContext context, long id, long groupCode)
        {
            if (context.Qq.ContainsGroup(groupCode))
            {
                var member = context.Qq.FindMemberFromGroupById(id, groupCode);
                if (member != null) return member;
            }
            var returnedGroupInfo = DataProvider.LoadGroupInfo(context.ToLoadGroupInfoRequest(groupCode, TimeHelper.MilliscondFromSeventy()));
            if (returnedGroupInfo == null) return null;
            var group = returnedGroupInfo.ConvertToView();
            context.Qq.AddGroup(group);
            return group.FindMemberById(id);
        }

        public static DisscussMember FindOrLoadDisscussMemberByName(this QQContext context, string nickName, long disscussId)
        {
            if (context.Qq.ContainsDisscuss(disscussId))
            {
                var member = context.Qq.FindMemberFromDisscussByName(nickName, disscussId);
                if (member != null) return member;
                if (SmartQQ.IsAtAll(nickName)) return null;
            }
            var returnedDisscussInfo = DataProvider.LoadDisscussInfo(context.ToLoadDisscussInfoRequest(disscussId, TimeHelper.MilliscondFromSeventy()));
            if (returnedDisscussInfo == null) return null;
            var disscuss = returnedDisscussInfo.ConvertToView(context);
            context.Qq.AddDisscuss(disscuss);
            return disscuss.FindMemberByName(nickName);
        }

        public static DisscussMember FindOrLoadDisscussMemberById(this QQContext context, long id, long disscussId)
        {
            if (context.Qq.ContainsDisscuss(disscussId))
            {
                var member = context.Qq.FindMemberFromDisscussById(id, disscussId);
                if (member != null) return member;
            }
            var returnedDisscussInfo = DataProvider.LoadDisscussInfo(context.ToLoadDisscussInfoRequest(disscussId, TimeHelper.MilliscondFromSeventy()));
            if (returnedDisscussInfo == null) return null;
            var disscuss = returnedDisscussInfo.ConvertToView(context);
            context.Qq.AddDisscuss(disscuss);
            return disscuss.FindMemberById(id);
        }

        public static void ReloadOwnerInfo(this QQContext context, long milliscond)
        {
            var userInfo = DataProvider.LoadOwnerInfo(context.ToLoadOwnerInfoRequest(milliscond));

            context.Qq.UserInfo = new UserInfo().ApplyReturned(userInfo);
        }

        public static void ReloadFriends(this QQContext context, long milliscond)
        {
            var friends = DataProvider.LoadFriends(context.ToLoadFriendRequest());
            var recents = DataProvider.LoadRecentFriends(context.ToLoadRecentRequest());
            var onlines = DataProvider.LoadOnlineFriends(context.ToLoadOnlineRequest(milliscond));
            var friendsInfo = LoadFriendsInfo(context, friends.Friends, milliscond);

            context.Qq.FriendManager = new FriendsManager();
            context.Qq.FriendManager.RecombinationFriends(context, friends, recents, onlines, friendsInfo);
        }

        public static void ReloadGroups(this QQContext context, long milliscond)
        {
            var groups = DataProvider.LoadGroups(context.ToLoadGroupRequest());
            var groupsInfo = LoadGroupsInfo(context, groups.Names, milliscond);
            
            context.Qq.GroupManager = new GroupsManager();
            context.Qq.GroupManager.RecombinationGroups(context, groups, groupsInfo);
        }

        public static void ReloadDisscusses(this QQContext context, long milliscond)
        {
            var disscusses = DataProvider.LoadDisscusses(context.ToLoadDisscussRequest(milliscond));
            var disscussesInfo = LoadDisscussesInfo(context, disscusses.Disscusses, milliscond);

            context.Qq.DisscussManager = new DisscussesManager();
            context.Qq.DisscussManager.RecombinationDisscusses(context, disscusses, disscussesInfo);
        }

        /// <summary>
        /// 获取好友详细信息
        /// </summary>
        private static List<ReturnedFriendInfo> LoadFriendsInfo(QQContext context, List<ReturnedUserFriends.Friend> friends, long milliscond)
        {
            var infos = new List<ReturnedFriendInfo>();
            Parallel.ForEach(friends, friend =>
            {
                var info = DataProvider.LoadFriendInfo(context.ToLoadFriendInfoRequest(friend.Uin, milliscond));
                if (info != null) infos.Add(info);
            });
            return infos;
        }

        /// <summary>
        /// 获取群组详细信息
        /// </summary>
        private static List<ReturnedGroupInfo> LoadGroupsInfo(QQContext context, List<ReturnedGroups.Group> groups, long milliscond)
        {
            var infos = new List<ReturnedGroupInfo>();
            Parallel.ForEach(groups, group =>
            {
                var info = DataProvider.LoadGroupInfo(context.ToLoadGroupInfoRequest(group.Code, milliscond));
                if (info != null) infos.Add(info);
            });
            return infos;
        }

        /// <summary>
        /// 获取讨论组详细信息
        /// </summary>
        private static List<ReturnedDisscussInfo> LoadDisscussesInfo(QQContext context, List<ReturnedDisscusses.Disscuss> disscusses, long milliscond)
        {
            var infos = new List<ReturnedDisscussInfo>();
            Parallel.ForEach(disscusses, disscuss =>
            {
                var info = DataProvider.LoadDisscussInfo(context.ToLoadDisscussInfoRequest(disscuss.Id, milliscond));
                if (info != null) infos.Add(info);
            });
            return infos;
        }

        #endregion Context Member Extension
    }
}
